#include "stdafx.h"
#include "msg/task.hpp"
#include "msg/taskmanager.hpp"
#include "msg/notification.hpp"
#include "stdlib/bugcheck.hpp"
#include "stdlib/exception.hpp"
using namespace JHCPP::stdlib;
using namespace JHCPP::stdlib::jhException;

namespace JHCPP
{
	namespace msg
	{
		CTask::CTask(const std::string& name)
		: m_name(name),
		m_pOwner(0),
		m_progress(0),
		m_state(TASK_IDLE),
		m_cancelEvent(false)
		{
		}

		const std::string& CTask::name() const
		{
			return m_name;
		}

		CTask::~CTask()
		{
		}

		float CTask::progress() const
		{
			CMutex::ScopedLock lock(m_mutex);

			return m_progress;
		}

		void CTask::cancel()
		{
			m_state = TASK_CANCELLING;
			m_cancelEvent.set();
			if (m_pOwner)
				m_pOwner->taskCancelled(this);
		}

		bool CTask::isCancelled() const
		{
			return m_state == TASK_CANCELLING;
		}

		CTask::TaskState CTask::state() const
		{
			return m_state;
		}

		void CTask::reset()
		{
			m_progress = 0.0;
			m_state    = TASK_IDLE;
			m_cancelEvent.reset();
		}

		void CTask::run()
		{
			CTaskManager* pOwner = getOwner();
			if (pOwner)
				pOwner->taskStarted(this);		
			try
			{
				m_state = TASK_RUNNING;
				runTask();
			}
			catch (CException& exc)
			{
				if (pOwner)
					pOwner->taskFailed(this, exc);
			}
			catch (std::exception& exc)
			{
				if (pOwner)
					pOwner->taskFailed(this, SystemException(exc.what()));
			}
			catch (...)
			{
				if (pOwner)
					pOwner->taskFailed(this, SystemException("unknown exception"));
			}
			m_state = TASK_FINISHED;
			if (pOwner)
				pOwner->taskFinished(this);
		}

		bool CTask::sleep(long milliseconds)
		{
			return m_cancelEvent.tryWait(milliseconds);
		}

		void CTask::setProgress(float progress)
		{
			CMutex::ScopedLock lock(m_mutex);

			m_progress = progress;
			if (m_pOwner)
				m_pOwner->taskProgress(this, m_progress);
		}

		void CTask::postNotification(CNotification* pNf)
		{
			jh_check_ptr (pNf);

			CMutex::ScopedLock lock(m_mutex);

			if (m_pOwner)
			{
				m_pOwner->postNotification(pNf);
			}
		}

		void CTask::setOwner(CTaskManager* pOwner)
		{
			CMutex::ScopedLock lock(m_mutex);

			m_pOwner = pOwner;
		}

		CTaskManager* CTask::getOwner() const
		{
			CMutex::ScopedLock lock(m_mutex);

			return m_pOwner;
		}

		void CTask::setState(TaskState state)
		{
			m_state = state;
		}

	}//end of namespace JHCPP
}//end of namespace msg
